\documentclass[twoside,colorback,accentcolor=tud4c,11pt]{tudreport}
\usepackage{ngerman}

\usepackage[utf8]{inputenc}

\usepackage{listings}
\lstset{
numbers=left,
numberstyle=\footnotesize,
frame=l,
breaklines=true,
basicstyle=\footnotesize,
showstringspaces=false
}
 
\usepackage[stable]{footmisc}
\usepackage[ngerman,pdfview=FitH,pdfstartview=FitV]{hyperref}

\usepackage{graphicx}
\usepackage{caption}
\usepackage{subcaption}
\usepackage{placeins} 
\usepackage{multicol}
\usepackage{booktabs}
\usepackage{multirow}
\usepackage{longtable}

\newlength{\longtablewidth}
\setlength{\longtablewidth}{0.675\linewidth}

\title{Praktikum adaptive Computersysteme}
\subtitle{Ausarbeitung\\6. Phase: Master-Mode Version}
\subsubtitle{Wilko Kunert, Alexander Schleich}
\lowertitleback{\hfill\today}
\institution{Embedded Systems \& Applications}

\begin{document}
\maketitle

\tableofcontents

\chapter{Einleitung}

In der 6. Phase des Praktikums \textit{Adaptive Computersysteme} soll die Bildbearbeitung in Form einer Kontrastberechnung nun komplett auf der Hardware erfolgen.
Die in \textit{C} geschriebene Software übergibt dabei lediglich folgende Parameter an die \textit{RCU}:

\begin{enumerate}
	\item{Die physikalische Adresse des Eingangsbildes;}
	\item{die physikalische Adresse des zu schreibenden Ausgangsbildes;}
	\item{die Anzahl der Datenworte;}
	\item{das Startkommando, welches die Berechnung in der Hardware auslöst.}
\end{enumerate}
 
Mithilfe dieser Parameter soll die Hardware selbstständig in der Lage sein, die
Bildpunktwerte aus dem Speicher auszulesen, die neuen Bildpunktwerte zu berechnen
sowie die neu berechneten Bildpunktwerte in den übergebenen Zielspeicherbereich 
zu schreiben.
Nach dem Ende der Berechnung werden von der Software lediglich das Ausgangsbild in
eine Datei geschrieben und die Zeitmessungsdaten ausgegeben.

\chapter{\textit{C}-Software}

Da in dieser Phase die Hardware bei der Problembearbeitung die Hauptrolle spielt, ist der Softwareteil sehr übersichtlich geblieben. Er muss nur das Eingangsbild in den Speicher schreiben, die in der Einführung aufgeführten Parameter sowie das Startkommando an die \textit{RCU} übertragen und anschließend das Ergebnis der Berechnung als Ausgangsbild abspeichern.

In Abbildung~\ref{fig:deklarationen} ist der erste Teil zu sehen: Dabei handelt es sich vor allem um die Deklaration bzw. Definition von Variablen und Konstanten und um die Überprüfung, ob das Programm mit korrekten Paramtern aufgerufen wurde.

\begin{figure}[h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=C,linewidth=0.9\linewidth}
\begin{lstlisting}
#include <stdio.h>
#include <stdlib.h>
#include <acev/rcu.h>

// Adresse des DMA-Basisregisters
#define REG_DMA_BASE   0x3BFFFFF

// Anzahl Datensaetze in Ein- und Ausgabedatei
#define NUM_WORDS 256*64

// Definitionen fuer RC Register
#define REG_SOURCE_ADDR   0
#define REG_DEST_ADDR     1
#define REG_COUNT         2
#define REG_START         3

// Hauptprogramm
main(
     int argc,     // Anzahl Kommandozeilenparameter + Programmname
     char *argv[]  // Programmname + Kommandozeilenparameter als Strings
     )
{
  // Zeiger auf Adressraum mit RC-Registern
  unsigned long volatile *rc;

  // Benutze vorzeichenlose Ganzzahlen fuer alle Variablen
  unsigned long volatile *inwords, *outwords,
    *inwords_phys, *outwords_phys;
    
  // Marker fuer Zeitmessung
  unsigned long long start, stop, rcu_get_ticks();

  // Eingabe- und Ausgabedatei
  FILE *infile, *outfile;

  // Eingabedatei oeffnen
  if ((infile = fopen(argv[1], "r")) == NULL) {
    printf("Eingabedatei %s konnte nicht geoeffnet werden.\n", argv[1]);
    exit(2);
  }

  // Ausgabedatei oeffnen
  if ((outfile = fopen(argv[2], "w")) == NULL) {
    printf("Ausgabedatei %s konnte nicht geoeffnet werden.\n", argv[2]);
    exit(3);
  } 

\end{lstlisting}
\end{minipage}
\caption{main.c - Deklarationen}
\label{fig:deklarationen}
\end{figure}

Abbildung~\ref{fig:vorbereitung} zeigt die Vorbereitungen für die Kommunikation mit der Hardware: Die \textit{RCU} wird initialisiert, der Speicher für das Ein- und Ausgangsbild allokiert, die physikalische Speicheradresse ermittelt, die Kopfdaten des Eingangsbildes kopiert und dessen restlicher Inhalt in den Speicher eingelesen. 

\begin{figure}[h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=C,linewidth=0.9\linewidth,firstnumber=47}
\begin{lstlisting}
  // RC initialisieren
  rcu_init();
  
  // Zeiger auf Adressraum mit RC-Registern holen
  rc = rcu_get_s0(NULL);

  // fordere Speicher fuer Ein- und Ausgabearrays an
  // *_phys zeigt auf die physikalische Speicheradresse
  // aus Sicht der Hardware
  inwords = rcu_malloc_master(2 * NUM_WORDS * sizeof(unsigned long),
			      (void **) &inwords_phys);
  outwords      = inwords      + NUM_WORDS;
  outwords_phys = inwords_phys + NUM_WORDS;

  // Setze DMA-Basisregister auf die naechstniedrigere 16MB-Grenze
  rc[REG_DMA_BASE] = (unsigned long) inwords_phys & 0xFF000000;

  if (!inwords || !inwords_phys) {
    fprintf(stderr, "out of memory\n");
    exit(1);
  }

  // Einlesen von Eingabedaten
  // Reiche PGM Kopfdatensatz direkt durch
  fgets((void*)inwords, 80, infile);
  fputs((void*)inwords,  outfile);
  fgets((void*)inwords, 80, infile);
  fputs((void*)inwords,  outfile);
  fgets((void*)inwords, 80, infile);
  fputs((void*)inwords,  outfile);

  // lese gesamtes Feld von Bildpunkten auf einen Satz
  fread(inwords, sizeof(unsigned char), 256*256, infile);
\end{lstlisting}
\end{minipage}
\caption{main.c - Vorbereitung für die Kommunikation mit der Hardware}
\label{fig:vorbereitung}
\end{figure}

Die eigentliche Kommunikation findet im Code aus Abbildung~\ref{fig:kommunikation} statt: Nachdem die Zeitmessung gestartet wird, werden die Parameter an die \textit{RCU} übertragen. Erst die physikalische Startadresse des Eingangsbildes im Speicher, dann die Zieladresse für das Ergebnis und anschließend die Anzahl der Datenworte - da das Bild 256x256 Bildpunkte à 8 Bit hat, beträgt die Anzahl der Datenworte 256x64, da ein Datenwort 32 Bit umfasst. Danach wird die Berechnung gestartet und durch \textit{rcu\_wait()} auf das Hardwareinterrupt gewartet, das den Abschluss der Berechnung anzeigt.

Die Ergebnisse werden im Anschluss in eine Datei geschrieben, der Speicher freigegeben und die Dateien geschlossen. Zuletzt wird die für die Bearbeitung benötigte Zeit ausgegeben.

\begin{figure}[h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=81}
\begin{lstlisting}
  // Merke Startzeit der Berechnung
  start = rcu_get_ticks();

  // Uebertrage Parameter an RC (nicht die Daten selbst)
  rc[REG_SOURCE_ADDR] = inwords_phys;  // physikalische(!) Startaddresse
  rc[REG_DEST_ADDR]   = outwords_phys; // physikalische(!) Zieladdresse
  rc[REG_COUNT]       = NUM_WORDS;     // anzahl datenworte

  rc[REG_START] = 1;                // startkommando

  // Warte auf Ende der Berechnung (wird ueber IRQ angezeigt)
  rcu_wait();

  // merke Stopzeit
  stop = rcu_get_ticks();

  // Hardware Interrupt zuruecksetzen durch beliebigen HW Lesezugriff
  rc[28];

  // gebe gesamtes Feld von Bildpunkten auf einen Satz aus
  fwrite(outwords, sizeof(unsigned char), 256*256, outfile);

  // Gebe Speicher fuer Ein-/Ausgabe-Arrays  wieder frei
  rcu_free_master((void *) inwords);

  // Dateien schliessen
  fclose(infile);
  fclose(outfile);

  // Gebe Ergebnis der Zeitmessung in Mikrosekunden aus
  printf("NUM_WORDS=%d\n", NUM_WORDS);
  printf("Zeit  : %8lld us\n", (stop-start)/TICKS_PER_USEC);
}
\end{lstlisting}
\end{minipage}
\caption{main.c - Kommunikation mit der Hardware}
\label{fig:kommunikation}
\end{figure}

\chapter{\textit{HDL}-Modell}

Die Hardware ist für die eigentliche Berechnung und somit für die gewünschte Kontrastspreizung verantwortlich. Hierfür müssen zuerst der hellste und der dunkelste Grauton des zu bearbeitenden Bildes ermittelt werden, um daraus eine Schrittweite zu errechnen, die für die eigentliche Spreizung benötigt wird. Aus diesem Grund muss zweimal über alle Bildpunkte iteriert werden.

\section{Moduldeklaration, Definitionen und Instanzierungen}

Neben den bereits aus den Slave-Mode bekannten In- und Outputs kommen in dieser Phase die Signale des Master-Mode hinzu: Diese bilden das Streaminterface, über welches mit dem Speicher kommuniziert werden kann. Abbildung~\ref{fig:moduldeklaration} zeigt die komplette Moduldeklaration.

In Abbildung~\ref{fig:definitionen} folgt die Definition der Konstanten und Variablen. Die Konstanten stehen für die einzelnen Zustände des endlichen Automaten, den wir für die Bearbeitung des Bildes verwenden. Jeden Zustand gibt es in einer \textit{*\_A}- und \textit{*\_B}-Variante, weil - wie bereits beschrieben - zweimal über das Bild bzw. den Eingangsstream iteriert werden muss. Bei den Variablen ist vor allem das \textit{RESULT}-Wire von Interesse, da dieses letztendlich die Ergebnisse liefert, die an die Zieladresse geschrieben werden sollen. Hierfür wird der aktuelle Bildpunkt vom Eingangsstream gelesen und da uns nur die letzten 8 Bit interessieren dieser mit \textit{'hff} verundet, der minimale gefundene Grauton abgezogen, für eine verbesserte Genauigkeit 4 Bits nach links geshiftet, mit der ermittelten Schrittweite multipliziert und das Ergebnis letztendlich 8 Bits nach recht geshiftet, damit wieder ein Wert zwischen 0 und 255 herauskommt.

Abbildung~\ref{fig:instanzierungen} zeigt die Erzeugung der Pipeline, welche die Information enthält, in welchem Takt ein Ergebnis des Dividierers übernommen werden soll, die Instanzierung des Dividierers für die Berechnung der Schrittweite und die Instanzierung der Flusskontrolle zur Steuerung der Streams. Der Dividierer besitzt einen 16 Bit breiten Eingang für den Dividenden sowie einen 8 Bit breiten Eingang für den Divisor und hat eine Latenz von 18 Takten.

\begin{figure}[h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth}
\begin{lstlisting}
`include "acsdefs.v"

module user (
             // *** Globale Signale
             CLK,                 // Takt 
             RESET,               // Chip Reset

             // *** Slave-Interface
             ADDRESSED,           // RC angesprochen im Slave-Mode
             WRITE,               // Schreibzugriff?
             DATAIN,              // Dateneingang
             DATAOUT,             // Datenausgang
             ADDRESS,             // Adresseingang
             IRQ,                 // Loest Interrupt (IRQ) an CPU aus

             // *** Stream-Interface
             STREAM_READ,        // Read-Datenbus
             STREAM_WRITE_PROG,  // Write-program-Datenbus
             STREAM_STALL,       // Stallsignale
             STREAM_ENABLE,      // Enables
             STREAM_FLUSH,       // Flushsignale
             STREAM_PROG         // Programsignale
             );

   // Eingaenge
   input						CLK;
   input						RESET;
   input						ADDRESSED;
   input						WRITE;
   input [31:0]				DATAIN;
   input [23:2]				ADDRESS;
   input [`STREAM_DATA_BUS]	STREAM_READ;
   input [`STREAM_CNTL_BUS]	STREAM_STALL;
   
   // Ausgaenge
   output [31:0]				DATAOUT;
   output [`STREAM_DATA_BUS]	STREAM_WRITE_PROG;
   output [`STREAM_CNTL_BUS]	STREAM_ENABLE;
   output [`STREAM_CNTL_BUS]	STREAM_FLUSH;
   output [`STREAM_CNTL_BUS]	STREAM_PROG;
   output					IRQ;

   // Deklaration fuer Stream-Interface
   wire [`STREAM_DATA_BUS]   STREAM_READ;
   wire [`STREAM_DATA_BUS]   STREAM_WRITE_PROG;
   wire [`STREAM_CNTL_BUS]   STREAM_STALL;
   wire [`STREAM_CNTL_BUS]   STREAM_ENABLE;
   reg [`STREAM_CNTL_BUS]    STREAM_FLUSH;
   reg [`STREAM_CNTL_BUS]    STREAM_PROG;
\end{lstlisting}
\end{minipage}
\caption{user.v - Moduldeklaration}
\label{fig:moduldeklaration}
\end{figure}

\begin{figure}[h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=51}
\begin{lstlisting}
   // FSM Zustaende
`define STATE_PROG_START_A  0   // programmiere Startadressen in Streams
`define STATE_PROG_COUNT_A  1   // programmiere Datensatzzahl in Streams
`define STATE_PROG_STEP_A   2   // programmiere Schrittweite in Streams
`define STATE_PROG_WIDTH_A  3   // programmiere Zugriffsbreite in Streams
`define STATE_PROG_MODE_A   4   // programmiere Betriebsart in Streams
`define STATE_COMPUTE_A     5   // fuehre Berechnung auf Streamdaten aus
`define STATE_WAIT_A        6   // Warte einen Takt zum Entleeren des Streams
`define STATE_SHUTDOWN_A    7   // Beende Berechnung
`define STATE_PROG_START_B  8   // programmiere Startadressen in Streams
`define STATE_PROG_COUNT_B  9   // programmiere Datensatzzahl in Streams
`define STATE_PROG_STEP_B   10  // programmiere Schrittweite in Streams
`define STATE_PROG_WIDTH_B  11  // programmiere Zugriffsbreite in Streams
`define STATE_PROG_MODE_B   12  // programmiere Betriebsart in Streams
`define STATE_COMPUTE_B     13  // fuehre Berechnung auf Streamdaten aus
`define STATE_WAIT_B        14  // Warte einen Takt zum Entleeren des Streams
`define STATE_SHUTDOWN_B    15  // Beende Berechnung

   reg          START;             // Wurde Anwendung gestartet?
   reg [31:0]   SOURCEADDR;        // Anfangsadresse der Eingabedaten
   reg [31:0]   DESTADDR;          // Anfangsadresse der Ausgabedaten
   reg [31:0]   COUNT_A, COUNT_B;  // Laenge der Daten
   reg          IRQSTATE;          // Loest Interrupt aus
   
   reg [4:0]    STATE;             // Aktueller Zustand der Anwendung
   reg          STREAMSTART;       // Sind Streams gestartet?

   reg [31:0]   STREAM_PROGDATA_0; // Programmierdaten-Register fuer Stream
   reg [31:0]   STREAM_PROGDATA_1; // Programmierdaten-Register fuer Stream

   wire [31:0]  WRITE_DATA;        // Daten

   // Abkuerzung fuer Registernummer 0 ... 15
   wire [3:0]   REGNUM = ADDRESS[5:2];

   // Streams laufen, nachdem sie gestartet worden sind und solange
   // noch Daten zu bearbeiten sind.
   wire RUNNING = (STREAMSTART && (COUNT_A != 0) && (COUNT_B != 0)) ? 1 : 0;
	   
   // Variablen fuer den Dividierer
   reg [15:0]    dividend;
   reg [7:0]     divisor;
   wire [15:0]   quot;
   wire [7:0]    remd;
   reg           overtakeQuot [0:17];

   reg [7:0]     minimum, maximum;
   reg [15:0]    stepSize;
   
   wire [31:0] RESULT = 
        ((((STREAM_READ[`STREAM_0] & 'hff) - minimum) << 4) * stepSize) >> 8;

\end{lstlisting}
\end{minipage}
\caption{user.v - Definitionen}
\label{fig:definitionen}
\end{figure}

\begin{figure}[h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=103}
\begin{lstlisting}
   generate
      genvar 	   i;
      for (i = 1; i < 18; i = i + 1) begin
	 always @(posedge CLK or posedge RESET) begin
	    if ((RESET) || (WRITE == 0)) begin
	       overtakeQuot[i] <= 0;
	    end else begin
	       overtakeQuot[i] <= overtakeQuot[i - 1];
	    end
	 end
      end
   endgenerate

   PipelinedDivider pd(.dividend(dividend),
		       .divisor(divisor),
		       .quot(quot),
		       .remd(remd),
		       .clk(CLK),
		       .rfd());
   
   // Flusskontrolle zwischen Ein- und Ausgabedatenstrom
   flowcontrol FC (
                   CLK,                   // Takt
                   RUNNING,               // Streams laufen lassen?
                   STREAM_STALL[0],       // Haengt Stream 0 (Eingabe-Strom)?
                   STREAM_STALL[1],       // Haengt Stream 1 (Ausgabe-Strom)?
                   RESULT,                // Von Anwendung zu schreibende Daten
                   STREAM_ENABLE[0],      // Stream 0 starten oder anhalten
                   STREAM_ENABLE[1],      // Stream 1 starten oder anhalten
                   WRITE_DATA             // Eingangsdaten fuer Ausgabe-Strom
                   );

   // Gebe IRQSTATE Register an CPU IRQ-Leitung aus
   assign IRQ = IRQSTATE;
   
   wire [31:0] 		     DATAOUT = { maximum, minimum, stepSize};

   // Schalte Streams zwischen Programmier- und Datenbetrieb um
   // Stream0 ist Lese-Stream, sein Eingang kann immer im Programmierbetrieb sein
   assign STREAM_WRITE_PROG[`STREAM_0] = STREAM_PROGDATA_0;
   // Stream1 ist Schreib-Stream, hier muss der Eingang umgeschaltet werden
   assign STREAM_WRITE_PROG[`STREAM_1] = (STREAM_PROG[1]) ?
                                         STREAM_PROGDATA_1 : WRITE_DATA;
\end{lstlisting}
\end{minipage}
\caption{user.v - Instanzierungen}
\label{fig:instanzierungen}
\end{figure}

\clearpage
\section{Endlicher Automat}

Die gesamte Logik steckt in einem \textit{always}-Block, der zum größten Teil aus einer \textit{Case}-Anweisung besteht. Dieser kann wiederum in zwei Phasen unterteilt werden: In Phase A werden die benötigten Werte für die Kontrastspreizung ermittelt und in Phase B wird die eigentliche Spreizung druchgeführt.

Abbildung~\ref{fig:reset} zeigt das Reset-Verhalten (Zeilen~153~bis~164), das Verhalten bei Slave-Zugriffen für die Übertragung der Parameter (Zeilen~168~bis~179) und die Übernahme von Ergebnissen des Dividierers (Zeilen~182~bis~184). In Zeile~172~und Zeile~173 wird die übertragene Wortanzahl vervierfacht (bzw. um 2 Bit nach links geshiftet), weil wir innerhalb der \textit{RCU} nicht auf 32 Bit Worten, sondern mit 8 Bit, welche einem Bildpunkt entsprechen, arbeiten.

\begin{figure}[h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=147}
\begin{lstlisting}
// Controller FSM ueberwacht gesamte Anwendung
   always @(posedge CLK or posedge RESET) begin
      // Initialisiere Register bei chip-weitem Reset
      if (RESET) begin
	 STATE             <= `STATE_PROG_START_A; 
	 IRQSTATE          <= 0;
	 STREAMSTART       <= 0; STREAM_PROG       <= 0;
	 STREAM_FLUSH      <= 0; STREAM_PROGDATA_0 <= 0;
	 STREAM_PROGDATA_1 <= 0; SOURCEADDR        <= 0;
	 DESTADDR          <= 0; COUNT_A           <= 0;
	 COUNT_B           <= 0; START             <= 0;
	 maximum            = 0; minimum            = 255;
	 overtakeQuot[0]   <= 0; stepSize          <= 0;
	 dividend          <= 16'hffff;
	 divisor           <= 8'h01;
	 
	 // Schreibzugriff auf RC, schreibe in entsprechendes Register
      end else if (ADDRESSED & WRITE) begin
	 case (REGNUM)
           0: SOURCEADDR   <= DATAIN;
           1: DESTADDR     <= DATAIN;
           2: begin
	      COUNT_A      <= DATAIN << 2;
	      COUNT_B      <= DATAIN << 2;
	   end
           3: begin 
              START        <= 1; // Startkommando, beginne Ausfuehrung
           end
           default: ;
	 endcase
      end else begin

	 if (overtakeQuot[17] == 1) begin
	    stepSize <= quot;
	 end
\end{lstlisting}
\end{minipage}
\caption{user.v - FSM: Reset und Slavezugriffe}
\label{fig:reset}
\end{figure}

\clearpage
\subsection{Phase A}

In Phase A werden alle Bildpunkte aus dem Read-Stream gelesen und das
Maximum und das Minimum ermittelt. Daraus wird im Endeffekt die Schrittweite nach der Formel 255 / (Maximum - Minimum) gewonnen.

Abbildung~\ref{fig:aprog} zeigt die Programmierung der Streams in fünf Zuständen:

\begin{enumerate}
	\item{`STATE\_PROG\_START\_A: Die Streams werden in den Programmiermodus umgeschaltet und die physikalischen Adressen des Ein- und Ausgangsbildes übernommen.}
	\item{`STATE\_PROG\_COUNT\_A: Die Anzahl der zu lesenden und schreibenden Datensätze wird übernommen. Der übertragene Wert wird dekrementiert, da die Zählung der Flusskontrolle mit null beginnt.}
	\item{`STATE\_PROG\_STEP\_A: Die Anzahl der gleichzeitig einzulesenden Datensätze wird übernommen - in diesem Fall wollen wir jeden Satz einzeln lesen.}
	\item{`STATE\_PROG\_WIDTH: Die Breite eines Datensatzes wird festgelegt. Da der Grauton eines Bildpunktes 8 Bit breit ist, sollen auch stets nur 8 Bit eingelesen werden.}
	\item{`STATE\_PROG\_MODE\_A: Den Streams wird mitgeteilt, ob auf sie schreibend oder lesend zugegriffen wird.}
\end{enumerate}

In Abbildung~\ref{fig:acompute} ist dann die eigentliche Berechnung zu sehen.
Zuerst wird der Programmiermodus abgeschaltet und anschließend in jedem Takt ein Datensatz eingelesen.
Da der erste gültige Datensatz erst ab dem zweiten Takt in diesem Zustand vorliegt, werden in Zeile~239 die beiden vorhandenen Counter verglichen, um die Ermittlung des Maximums und Minimums im ersten Durchlauf zu deaktivieren.
Bei der eigentlichen Ermittlung wird der gelesen Datensatz - wie auch beim \textit{RESULT}-Wire - mit \textit{'hff} verundet, um die Breite von 32 Bit auf 8 Bit zu kürzen: In den ersten 24 Bit stehen für uns nicht relevante Werte, in den letzten 8 Bit steht der Wert des aktuellen Grautons.
Dieser wird mit dem bisherigen Maximum bzw. Minimum verglichen und ersetzt diese gegebenenfalls.
Der Dividierer wird in jedem Takt mit den gewonnenen Daten beschickt, für die spätere Berechnung wird aber nur das zuletzt errechnete Ergebnis genommen.
Für eine verbesserte Genauigkeit shiften wir auch hier den Dividenden um 4 Bits nach links, rechnen also nicht mit 255 sondern mit 4080. Die Differenz aus Minimum und Maximum bildet den Divisor.
Sobald alle Datensätze abgearbeitet sind, wird der Counter wieder auf 1 gesetzt, da dieser Wert für das \textit{RUNNING}-Wire gebraucht wird (vgl. Abbildung~\ref{fig:definitionen}). Nachdem die Streams geflusht wurden beginnt Phase B der Berechnung.

\begin{figure}[!h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=183}
\begin{lstlisting}
 // CPU hat Berechnung gestartet, keine Slave-Mode Zugriffe mehr moeglich
	 if (START) begin
            case (STATE)
	      `STATE_PROG_START_A:
		begin
		   // Beide Streams in Programmierungsmodus schalten
		   STREAM_PROG[1:0]  <= 2'b11;
		   // Anfangsadresse fuer Stream 0 schreiben
		   STREAM_PROGDATA_0 <= SOURCEADDR;
		   // Anfangsadresse fuer Stream 1 schreiben
		   STREAM_PROGDATA_1 <= DESTADDR;
		   // FSM weitersetzen
		   STATE <=  `STATE_PROG_COUNT_A;
		end
	      `STATE_PROG_COUNT_A:
		begin
		   // Anzahl Datensaetze - 1 (bei beiden Streams gleich)
		   STREAM_PROGDATA_0 <= COUNT_A - 1;
		   STREAM_PROGDATA_1 <= COUNT_A - 1;
		   // FSM weitersetzen
		   STATE <=  `STATE_PROG_STEP_A;
		end
	      `STATE_PROG_STEP_A:
		begin
		   // Schrittweite: 1 Datensatz (bei beiden Streams gleich)
		   STREAM_PROGDATA_0 <= 1;
		   STREAM_PROGDATA_1 <= 1;
		   // FSM weitersetzen
		   STATE <=  `STATE_PROG_WIDTH_A;
		end 
	      `STATE_PROG_WIDTH_A:
		begin
		   // Wordbreite der Zugriffe: 8b (bei beiden Streams gleich)
		   STREAM_PROGDATA_0 <= 8;//
		   STREAM_PROGDATA_1 <= 8;//
		   // FSM weitersetzen
		   STATE <=  `STATE_PROG_MODE_A;		 
		end
	      `STATE_PROG_MODE_A: 
		begin
		   // Zugriffsart fuer Stream 0: Lesen
		   STREAM_PROGDATA_0 <= `STREAM_READ;
		   // Zugriffsart fuer Stream 1: Schreiben
		   STREAM_PROGDATA_1 <= `STREAM_WRITE;
		   // FSM weitersetzen
		   STATE <=  `STATE_COMPUTE_A;		 
		end
\end{lstlisting}
\end{minipage}
\caption{user.v - Phase A: Programmierung}
\label{fig:aprog}
\end{figure}

\begin{figure}[!h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=230}
\begin{lstlisting}
	      `STATE_COMPUTE_A: begin
		 // Programmiermodus fuer beide Streams abschalten
		 STREAM_PROG[1:0]   <= 0;
		 // Beide Streams starten (via flowcontrol-Modul)
		 STREAMSTART <= 1;

		 if (COUNT_A != COUNT_B) begin // erst ab der zweiten Iteration
		    
		    if ((STREAM_READ[`STREAM_0] & 'hff) > maximum) begin
		       maximum = STREAM_READ[`STREAM_0];
		    end
		    if ((STREAM_READ[`STREAM_0] & 'hff) < minimum) begin
		       minimum = STREAM_READ[`STREAM_0];
		    end

		    dividend <= 255 << 4;
		    divisor <= (maximum - minimum);
		    overtakeQuot[0] <= 1;
		 end
		 
		 // Alle Datensaetze bearbeitet?
		 if (COUNT_A == 0) begin
                    // Dann beide Streams stoppen
                    STREAMSTART <= 0;
                    // Falls Write-Stream fertig
                    if (!STREAM_STALL[1]) begin
		       // alle noch gepufferten Daten wirklich schreiben
		       STREAM_FLUSH[1] <= 1;
		       // FSM weitersetzen
		       STATE <= `STATE_WAIT_A;
		       COUNT_A <= 1;
                    end
		 end else if (STREAM_ENABLE[0] & ~STREAM_STALL[0]) begin
                    // Nur dann einen Datensatz als bearbeitet zaehlen,
                    // wenn Stream 0 aktiv liest (ENABLE) und nicht haengt (!STALL)
                    COUNT_A <= COUNT_A - 1;
		 end
	      end  
	      `STATE_WAIT_A: begin
		 STATE <=  `STATE_SHUTDOWN_A;
	      end
	      `STATE_SHUTDOWN_A: begin
		 if (!STREAM_STALL[1]) begin
                    // ja, Leerung beenden
                    STREAM_FLUSH[1] <= 0;
		    STATE <=  `STATE_PROG_START_B;
		 end
	      end       
\end{lstlisting}
\end{minipage}
\caption{user.v - Phase A: Berechnung}
\label{fig:acompute}
\end{figure}

\clearpage
\subsection{Phase B}

In Phase B wird lediglich noch einmal über die Bildpunkte iteriert, damit das Bild auch wirklich gespreizt wird. Die eigentliche Berechnung der Spreizung findet über das \textit{RESULT}-Wire aus Abbildung~\ref{fig:definitionen} statt.

Die Programmierung der Streams in Abbildung~\ref{fig:bprog} geschieht analog zur Phase A. Auch die ``Berechnung'', die in Abbildung~\ref{fig:bcompute} zu sehen ist, geschieht nahezu analog zu Phase A, allerdings werden in dieser Phase keine Minima, Maxima oder Schrittweiten mehr ermittelt. Sobald über alle Bildpunkte des Streams iteriert wurde, werden die Counter auf null gesetzt und zeigen damit an, dass die Streams nicht mehr laufen. Zum Abschluss wird der Hardwareinterrupt ausgelöst, um der Software das Ende der Berechnung anzuzeigen. Die Hardware wäre nun für die nächste Berechnung bereit.

\begin{figure}[!h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=278}
\begin{lstlisting}
             `STATE_PROG_START_B: 
		begin
		   // Beide Streams in Programmierungsmodus schalten
		   STREAM_PROG[1:0]  <= 2'b11;
		   // Anfangsadresse fuer Stream 0 schreiben
		   STREAM_PROGDATA_0 <= SOURCEADDR;
		   // Anfangsadresse fuer Stream 1 schreiben
		   STREAM_PROGDATA_1 <= DESTADDR;
		   // FSM weitersetzen
		   STATE <= `STATE_PROG_COUNT_B;
		end
              `STATE_PROG_COUNT_B: 
		begin
		   // Anzahl Datensaetze - 1 (bei beiden Streams gleich)
		   STREAM_PROGDATA_0 <= COUNT_B - 1;
		   STREAM_PROGDATA_1 <= COUNT_B - 1;
		   // FSM weitersetzen
		   STATE <= `STATE_PROG_STEP_B;
		end
              `STATE_PROG_STEP_B: 
		begin
		   // Schrittweite: 1 Datensatz (bei beiden Streams gleich)
		   STREAM_PROGDATA_0 <= 1;
		   STREAM_PROGDATA_1 <= 1;
		   // FSM weitersetzen
		   STATE <= `STATE_PROG_WIDTH_B;
		end
              `STATE_PROG_WIDTH_B: 
		begin
		   // Wordbreite der Zugriffe: 8b (bei beiden Streams gleich)
		   STREAM_PROGDATA_0 <= 8;
		   STREAM_PROGDATA_1 <= 8;
		   // FSM weitersetzen
		   STATE <= `STATE_PROG_MODE_B;
		end
              `STATE_PROG_MODE_B: 
		begin
		   // Zugriffsart fuer Stream 0: Lesen
		   STREAM_PROGDATA_0 <= `STREAM_READ;
		   // Zugriffsart fuer Stream 1: Schreiben
		   STREAM_PROGDATA_1 <= `STREAM_WRITE;
		   // FSM weitersetzen
		   STATE <= `STATE_COMPUTE_B;
		end
\end{lstlisting}
\end{minipage}
\caption{user.v - Phase B: Programmierung}
\label{fig:bprog}
\end{figure}

\begin{figure}[!h]
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=322}
\begin{lstlisting}
              `STATE_COMPUTE_B: 
		begin
		   // Programmiermodus fuer beide Streams abschalten
		   STREAM_PROG[1:0]   <= 0;
		   // Beide Streams starten (via flowcontrol-Modul)
		   STREAMSTART <= 1;

		   // Alle Datensaetze bearbeitet?
		   if (COUNT_B == 0) begin
                      // Dann beide Streams stoppen
                      STREAMSTART <= 0;
                      // Falls Write-Stream fertig
                      if (!STREAM_STALL[1]) begin
			 // alle noch gepufferten Daten wirklich schreiben
			 STREAM_FLUSH[1] <= 1;
			 // FSM weitersetzen
			 STATE <= `STATE_WAIT_B;
			 COUNT_A <= 0;
                      end
		   end else if (STREAM_ENABLE[0] & ~STREAM_STALL[0])
                     // Nur dann einen Datensatz als bearbeitet zaehlen,
                     // wenn Stream 0 aktiv liest (ENABLE) und nicht haengt (!STALL)
                     COUNT_B <= COUNT_B - 1;
		end
              `STATE_WAIT_B:
		begin
                   STATE <= `STATE_SHUTDOWN_B;
		end
              `STATE_SHUTDOWN_B: 
		begin
                   // Ist Schreibpuffer schon komplett geleert?
                   if (!STREAM_STALL[1]) begin
                      // ja, Leerung beenden
                      STREAM_FLUSH[1] <= 0;
                      // CPU durch IRQ Fertigwerden der RC anzeigen
                      IRQSTATE <= 1;
                      // FSM stoppen (RC jetzt wieder im Slave-Mode)
                      START <= 0;
                      // FSM auf Startzustand zuruecksetzen
                      STATE <= `STATE_PROG_START_B;
                   end
		end
              // sollte nicht auftreten, nur fuer Logikoptimierung
              default: STATE <='bx;
            endcase
	 end
	 // Bei jedem Zugriff auf RC im Slave-Mode, IRQ ausschalten
	 else if (ADDRESSED)
	   IRQSTATE <= 0;
      end
   end
\end{lstlisting}
\end{minipage}
\caption{user.v - Phase B: Berechnung}
\label{fig:bcompute}
\end{figure}

\chapter{Simulation}

\section{Stimulus}

Die Stimulus-Datei liest eine input.mem Datei, schreibt die bereits bekannten
Parameter in die Hardware und gibt nach dem Interrupt die neuen Werte in der
output.mem Datei aus.

\begin{figure}[!h] 
\centering
\begin{minipage}{\linewidth}
\lstset{language=Verilog,linewidth=0.9\linewidth,firstnumber=58}
\begin{lstlisting}
    ...
	
    // Eingabedaten aus Datei lesen
    ReadMemFile("input.mem");
    // Startadresse 4 in Register 0 schreiben
    Write32(`SLAVE_BASE + 32'h0, 32'h00000004);

    // Zieladresse 4096 in Register 1 schreiben
    Write32(`SLAVE_BASE + 32'h4, 32'h00001000);

    // Datensatzlaenge 48 in Register 2 schreiben
    Write32(`SLAVE_BASE + 32'h8, 32'h00000002);
    
    // RC starten durch Schreiben auf Register 3
    Write32(`SLAVE_BASE + 32'hc, 32'h00000001);

    // Warte, bis RC durch IRQ das Ende anzeigt
    RunUntilInterrupt;

    // Ausgabedaten in Datei schreiben
    WriteMemFile("output.mem", 32'h00001000, 32'h0000002);
    
    ...
\end{lstlisting}
\end{minipage}
\caption{user.v - Phase A Berechnung}
\end{figure}


\section{Ein-/Ausgabedateien}


Der Einfachheit halber haben wir in unserer input.mem Datei lediglich acht
verschiedene Zahlen (8 Bit wie gehabt), die in zwei Schritten an die Hardware
übertragen werden.
Im Detail ergeben sich daraus folgende acht Zahlen, hier Eingabe und Ausgabe
gegenübergestellt:\\

 \begin{tabular}{lcl}  
	\centering
   Eingabe & & Ausgabe\\	
   \hline
   1. 0x0A = 10 & -> & 0x00 = 0 \\
   2. 0x0F = 15 & -> & 0x06 = 6 \\
   3. 0xC8 = 200 & -> & 0xF9 = 249 \\
   4. 0xA0 = 160 & -> & 0xC4 = 196 \\
   5. 0xB1 = 177 & -> & 0xDB = 219 \\
   6. 0xC6 = 198 & -> & 0xF6 = 246 \\
   7. 0x0E = 14 & -> & 0x05 = 5 \\
   8. 0x4B = 75 & -> & 0x55 = 85 \\
 \end{tabular}

\section{Waveforms}  

Auf der ersten Waveform (Abbildung~\ref{fig:waveProg}) ist der Programmiervorgang in Phase A zu
sehen. Die interessanten Signale sind hier: DATAIN, STREAM\_PROGDATA\_0/1 sowie
STATE. Hier ist zu erkennen, dass die korrekten Programmierungen in die Streams
geschrieben werden sowie der Start der FSM inklusive der ersten fünf Zustände.
 

\begin{figure}[hbt]
\centering 
\includegraphics[width=1\textwidth]{graphics/waveforms/programmStreams_cropped_commented_01.png}
\caption{Simulation - Stream-Programmierung}
\label{fig:waveProg}
\end{figure} 
 
Auf der zweiten Waveform (Abbildung~\ref{fig:waveMinMax}) ist gut erkenntbar, wie in acht
Schritten die Zahlen eingelesen werden (Signal STREAM\_READ). Die Zahlen vor den
rot markierten kommen dadurch zustande, dass unsere Software (bzw. hier der
Stimulus) 32 Bit große Zahlen schickt, der Stream diese aber in 8 Bit Schritten
abarbeitet.

Mithilfe dieser Zahlen werden Minimum und Maximum in den folgenden Takten berechnet.
Nach jedem Lesevorgang wird COUNT\_A um 1 reduziert.
 
\begin{figure}[hbt]
\centering 
\includegraphics[width=1\textwidth]{graphics/waveforms/minMaxBerechnung_cropped_commented_01.png}
\caption{Simulation - Min/Max-Berechnung}
\label{fig:waveMinMax}
\end{figure}  
 
Auf der letzten Waveform (Abbildung~\ref{fig:waveWrite}) werden die Zahlen erneut
eingelesen und währendessen automatisch daraus die neuen Zahlen in RESULT
berechnet, gespeichert und direkt wieder in WRITE\_DATA geschrieben. 
Nach Ende des Lesevorgangs sind alle neuen Zahlen bereits berechnet und
geschrieben.

Zusätzlich ist noch das Setzen von IRQSTATE zu erkennen, welches mit dem IRQ
Ausgang verbunden ist. Dadurch wird dem Stimulus das Ende der Berechnung
mitgeteilt.
 
 
\begin{figure}[hbt]
\centering 
\includegraphics[width=1\textwidth]{graphics/waveforms/neueWerteSchreiben_cropped_commented_01.png}
\caption{Simulation - Neue Werte berechnen und schreiben}
\label{fig:waveWrite}
\end{figure} 

\chapter{Ergebnis}

Auch hier erfüllt das Ergebnis die Aufgabenstellung. In den unteren Abbildungen ist die erfolgreiche Aufspreizung des Kontrastes gut erkennbar.

Die Laufzeit unserer Lösung beträgt 1485µs. Im Vergleich zu unserer Softwarelösung aus der letzten Phase, welche eine Laufzeit von 110222µs hatte, ist dies eine beachtliche Steigerung. Hierbei gilt es allerdings zu beachten, dass wir bei der letzten Zeitmessung das Einlesen und Speichern der Bilder mit einbezogen und statt mit 32 Bit nur mit 8 Bit breiten Datenworten mit der \textit{RCU} kommuniziert haben.

\begin{figure}[h]
\centering
\begin{subfigure}[b]{0.45\textwidth}
\centering
\includegraphics[width=\textwidth]{graphics/lena256.png}
\caption{lena256.pgm}
\end{subfigure}
\begin{subfigure}[b]{0.45\textwidth}
\centering
\includegraphics[width=\textwidth]{graphics/lena256c.png}
\caption{lena256c.pgm}
\end{subfigure}
\caption{Kontrastspreizung}
\label{fig:kontrastspreizung}
\end{figure}
\end{document}
